package com.doge.walknovel.business.reader.download

import com.doge.walknovel.api.model.ChapterInfo
import com.doge.walknovel.api.model.TextInfo
import com.doge.walknovel.core.base.LoadStatus
import com.doge.walknovel.core.sync.ResultBox
import com.doge.walknovel.utils.*
import com.liulishuo.okdownload.DownloadTask
import com.liulishuo.okdownload.core.cause.EndCause
import java.io.*
import java.nio.charset.StandardCharsets

object ChapterTextCacheHelper {
    private val novelsDir: File get() {
        return File(appContext.externalCacheDir?.parent, "files/novelTexts").apply {
            if (!exists()) mkdirs()
        }
    }

    /** 异步下载并获得文件内容 */
    fun requireChapterText(novelId: Int, chapter: ChapterInfo): List<TextInfo> {
        require(!isMainThread())
        log("ChapterTextHelper require novelId $novelId chapter $chapter ${chapter.filePath}")

        val text = chapter.text
        if (text?.isNotEmpty() == true) {
            log("ChapterTextHelper require parseTextToMemory [$novelId $chapter] completed")
            return parseTextToMemory(text, chapter.chapterId)
        }

        val remotePath = chapter.filePath ?: return provideErrorTxtInfo(chapter.chapterId, "filePath is null")
        val fileName = chapter.fileName ?: return provideErrorTxtInfo(chapter.chapterId, "fileName is null")
        val novelDir = File(novelsDir, novelId.toString()).apply {
            if (!exists()) mkdirs()
        }
        val localFile = File(novelDir, "${fileName}.txt")
        if (!localFile.exists()) { // todo 文件完整性校验
            log("ChapterTextHelper require download [$novelId $chapter] start ")
            val resultDownload = download(remotePath, novelDir, fileName)
            log("ChapterTextHelper require download [$novelId $chapter] completed $resultDownload ")
            val zipLocalFile = File(novelDir, "${fileName}.zip")
            val zipPassword = "${novelId}_${chapter.chapterId}".md5
            log("ChapterTextHelper require unzip [$novelId $chapter] start pwd $zipPassword")
            val resultUnzip = unzip(zipLocalFile.absolutePath, novelDir.absolutePath, zipPassword)
            log("ChapterTextHelper require unzip [$novelId $chapter] completed $resultUnzip")
        } else {
            log("ChapterTextHelper require local exists [$novelId $chapter] completed")
        }
        if (localFile.exists()) {
            log("ChapterTextHelper require parseStreamToMemory [$novelId $chapter] completed")
            return parseStreamToMemory(localFile.inputStream(), chapter.chapterId)
        }
        log("ChapterTextHelper require resource error [$novelId $chapter]")
        // todo delete file 触发重新下载
        return provideErrorTxtInfo(chapter.chapterId, "require resource error")
    }

    private fun parseStreamToMemory(stream: InputStream, chapterId: Int): List<TextInfo> {
        val result = mutableListOf<TextInfo>()

        var inputStream: InputStreamReader? = null
        var reader: BufferedReader? = null
        try {
            inputStream = InputStreamReader(stream, StandardCharsets.UTF_8)
            reader = BufferedReader(inputStream)
            var idx = 0
            var line: String? = reader.readLine()
            while (line != null) {
                result.add(TextInfo(chapterId, idx++, LoadStatus.SUCCESS, line))
                line = reader.readLine()
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        } finally {
            closeQuietly(reader)
            closeQuietly(inputStream)
            closeQuietly(stream)
        }
        return result
    }

    private fun parseTextToMemory(text: String, chapterId: Int): List<TextInfo> {
        return listOf(TextInfo(chapterId, 0, LoadStatus.SUCCESS, text))
    }

    private fun unzip(
        zipPath: String,
        outputDir: String,
        password: String
    ): Boolean {
        log("ChapterTextHelper start unzip zipPath $zipPath outputDir $outputDir password $password")
        require(!isMainThread())
        return try {
            ZipHelper.unzip(zipPath, outputDir, password)
            true
        } catch (e: Throwable) {
            e.printStackTrace()
            false
        }
    }

    private fun download(
        downloadUrl: String,
        fileDir: File,
        fileName: String
    ): Boolean {
        require(!isMainThread())
        log("ChapterTextHelper start download downloadUrl $downloadUrl fileDir $fileDir fileName $fileName")
        val result = ResultBox(false)

        val task = DownloadTask.Builder(downloadUrl, fileDir)
            .setFilename("${fileName}.zip")
            .setConnectionCount(1)
            .setMinIntervalMillisCallbackProcess(300)
            .setPassIfAlreadyCompleted(false)
            .build()
        task.execute(DownloadListenerAdapter(fileName) {
            when (it) {
                EndCause.COMPLETED -> result.setAndNotify(true)
                else -> result.setAndNotify(false)
            }
        })
        return result.blockedGet() ?: false
    }

    private fun provideErrorTxtInfo(chapterId: Int, info: String): List<TextInfo> {
        feedback("chapterLoadError", info, chapterId.toString())
        return listOf(TextInfo.error(chapterId))
    }
}